package pay

import (
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-pay/gopay/apple"
	"github.com/go-pay/gopay/pkg/xlog"
	"github.com/pkg/errors"
	"gpt-api/framework/ginplus"
	"gpt-api/framework/log"
	"io"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
)

type Apple struct {
}

func (a *Apple) QueryOrder(OrderID string) (string, error) {
	//TODO implement me
	panic("implement me")
}

func NewApple() Payer {
	return &Apple{}
}

func (a *Apple) Order(_ *OrderParams) (string, error) {
	return "", nil
}

func (a *Apple) verifyReceipt(data string) (vr *apple.VerifyResponse, err error) {
	config := strings.NewReader(fmt.Sprintf(`{"receipt-data": "%s","password": "fcc553da99a14b179b361afb08d2182d"}`, data))
	//resp, err := http.DefaultClient.Post(apple.UrlProd, "application/json", config)

	resp, err := http.DefaultClient.Post(apple.UrlSandbox, "application/json", config)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	bs, err := ioutil.ReadAll(io.LimitReader(resp.Body, int64(5<<20))) // default 5MB change the size you want
	if err != nil {
		return nil, err
	}
	err = json.Unmarshal(bs, &vr)
	return
}

func (a *Apple) verifyReceiptProduce(data string) (vr *apple.VerifyResponse, err error) {
	config := strings.NewReader(fmt.Sprintf(`{"receipt-data": "%s","password": "fcc553da99a14b179b361afb08d2182d"}`, data))
	//resp, err := http.DefaultClient.Post(apple.UrlProd, "application/json", config)

	resp, err := http.DefaultClient.Post(apple.UrlProd, "application/json", config)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	bs, err := ioutil.ReadAll(io.LimitReader(resp.Body, int64(5<<20))) // default 5MB change the size you want
	if err != nil {
		return nil, err
	}
	err = json.Unmarshal(bs, &vr)
	return
}

func (a *Apple) Notify(c *gin.Context, callback func(req *NotifyReq) error) error {
	var request struct {
		ReceiptData string `json:"receipt_data" binding:"required"`
		EquipmentId string `json:"equipment_id" binding:"required"`
		Mark        int64  `json:"mark"`
	}

	if err := c.Bind(&request); err != nil {
		return ginplus.ReplyBadRequest(c, err)
	}

	resp, _ := a.verifyReceiptProduce(request.ReceiptData)
	switch resp.Status {
	case 21007:

		Resp, err := a.verifyReceipt(request.ReceiptData) //沙盒
		//fmt.Println("沙盒", Resp)
		if err != nil {
			return err
		}
		if Resp.Status != 0 {
			return ginplus.ReplyBadRequest(c, errors.New("verify fail"))
		}
		//fmt.Println("Resp.Receipt", Resp.Receipt.InApp)
		if Resp.Receipt == nil {
			return ginplus.ReplyBadRequest(c, errors.New("data invalid"))
		}
		for _, result := range Resp.Receipt.InApp {
			log.Info("shoujun result", log.Var("result", result))
			ex, err := strconv.ParseInt(result.ExpiresDateTimestamp, 10, 64)
			req := NotifyReq{
				UserID:          request.EquipmentId,
				Channel:         AppleChannel,
				AppleProductID:  result.ProductId,
				TradeNo:         result.TransactionId,
				OriginalTradeNo: result.OriginalTransactionId,
				ExTime:          ex,
				Mark:            request.Mark,
			}
			if err = callback(&req); err != nil {
				return err
			}
		}
		return ginplus.ReplyJSON(c, nil)

	case 0:
		break
	default:
		return ginplus.ReplyBadRequest(c, errors.New("verify fail"))
	}

	for _, result := range resp.Receipt.InApp {
		log.Info("shoujun result", log.Var("result", result))

		ex, err := strconv.ParseInt(result.ExpiresDateTimestamp, 10, 64)
		req := NotifyReq{
			UserID:          request.EquipmentId,
			Channel:         AppleChannel,
			AppleProductID:  result.ProductId,
			TradeNo:         result.TransactionId,
			OriginalTradeNo: result.OriginalTransactionId,
			ExTime:          ex,
			Mark:            request.Mark,
		}
		if err = callback(&req); err != nil {
			return err
		}
	}

	return ginplus.ReplyJSON(c, nil)
}

func (a *Apple) Notification(c *gin.Context, callback func(req *NotifyReq) error) error {
	var request struct {
		SignedPayload string `json:"signedPayload" binding:"required"`
	}
	if err := c.Bind(&request); err != nil {
		return ginplus.ReplyBadRequest(c, err)
	}
	// decode signedPayload
	payload, err := apple.DecodeSignedPayload(request.SignedPayload)
	if err != nil {
		xlog.Error(err)
		return err
	}
	xlog.Debugf("payload.NotificationType: %s", payload.NotificationType)
	xlog.Debugf("payload.Subtype: %s", payload.Subtype)
	xlog.Debugf("payload.NotificationUUID: %s", payload.NotificationUUID)
	xlog.Debugf("payload.NotificationVersion: %s", payload.NotificationVersion)
	xlog.Debugf("payload.Data: %+v", payload.Data)
	bs1, _ := json.Marshal(payload)
	xlog.Color(xlog.RedBright).Info(string(bs1))
	log.Info("payload.NotificationType", log.Var("payload.NotificationType", payload.NotificationType))

	/*
	   {
	       "notificationType":"DID_RENEW",
	       "subtype":"",
	       "notificationUUID":"469bf30e-7715-4f9f-aae3-a7bfc12aea77",
	       "notificationVersion":"",
	       "data":{
	           "appAppleId":0,
	           "bundleId":"com.audaos.audarecorder",
	           "bundleVersion":"7",
	           "environment":"Sandbox",
	           "signedRenewalInfo":"xxxxxxxxxx",
	           "signedTransactionInfo":"xxxxxxxxxxx"
	       }
	   }
	*/

	// decode renewalInfo
	renewalInfo, err := payload.DecodeRenewalInfo()
	if err != nil {
		xlog.Error(err)
		return err
	}
	xlog.Debugf("data.renewalInfo: %+v", renewalInfo)
	bs, _ := json.Marshal(renewalInfo)
	xlog.Color(xlog.GreenBright).Info(string(bs))
	log.Info("shoujun renewalInfo", log.Var("renewalInfo", string(bs)))
	/*
	   {
	       "autoRenewProductId":"com.audaos.audarecorder.vip.m2",
	       "autoRenewStatus":1,
	       "expirationIntent":0,
	       "gracePeriodExpiresDate":0,
	       "isInBillingRetryPeriod":false,
	       "offerIdentifier":"",
	       "offerType":0,
	       "originalTransactionId":"2000000000842607",
	       "priceIncreaseStatus":0,
	       "productId":"com.audaos.audarecorder.vip.m2",
	       "signedDate":1646387008228
	   }
	*/

	// decode transactionInfo
	transactionInfo, err := payload.DecodeTransactionInfo()
	if err != nil {
		xlog.Error(err)
		return err
	}
	xlog.Debugf("data.transactionInfo: %+v", transactionInfo)
	bs2, _ := json.Marshal(transactionInfo)
	xlog.Color(xlog.YellowBright).Info(string(bs2))
	log.Info("shoujun transactionInfo", log.Var("transactionInfo", string(bs2)))

	req := NotifyReq{
		Channel:         AppleChannel,
		AppleProductID:  transactionInfo.ProductId,
		TradeNo:         transactionInfo.TransactionId,
		OriginalTradeNo: transactionInfo.OriginalTransactionId,
		ExTime:          transactionInfo.ExpiresDate,
	}
	if err = callback(&req); err != nil {
		return err
	}
	/*
	   {
	       "appAccountToken":"",
	       "bundleId":"com.audaos.audarecorder",
	       "expiresDate":1646387196000,
	       "inAppOwnershipType":"PURCHASED",
	       "isUpgraded":false,
	       "offerIdentifier":"",
	       "offerType":0,
	       "originalPurchaseDate":1646046037000,
	       "originalTransactionId":"2000000000842607",
	       "productId":"com.audaos.audarecorder.vip.m2",
	       "purchaseDate":1646387016000,
	       "quantity":1,
	       "revocationDate":0,
	       "revocationReason":"",
	       "signedDate":1646387008254,
	       "subscriptionGroupIdentifier":"20929536",
	       "transactionId":"2000000004047119",
	       "type":"Auto-Renewable Subscription",
	       "webOrderLineItemId":"2000000000302832"
	   }
	*/
	return ginplus.ReplyJSON(c, nil)
}
